#ifndef DocumentContext_h
#define DocumentContext_h

#include "simodo/lsp-server/MessageFullContent.h"

#include "simodo/variable/Variable.h"
#include "simodo/lsp-client/CompletionParams.h"

#include <shared_mutex>
#include <set>

namespace simodo::lsp
{
    class ServerContext;
    class DocumentOperationFactory_interface;
    class DocumentOperation_interface;

    class DocumentContext
    {
        ServerContext &         _server;
        std::unique_ptr<DocumentOperation_interface> 
                                _op;

        /// @note Делать эти флаги Atomic необязательно, тк в критических местах они закрываются
        /// на запись мютексом `_analyze_data_mutex`, а там где осталась вероятность перепутывания
        /// значения между нитями процессора - это не критично. Вроде бы.
        bool                    _valid;   
        bool                    _is_opened = false; 

        std::string             _uri;
        std::string             _languageId;
        std::u16string          _text;
        int64_t                 _version = 0;
        std::string             _file_name;

        mutable std::shared_timed_mutex _analyze_data_mutex;

    public:
        DocumentContext() = delete;
        DocumentContext(ServerContext &server,
                        const std::string & languageId,
                        const variable::Object &textDocument_object);

        bool valid() const { return _valid; }
        bool is_opened() const { return _is_opened; }

        const ServerContext &   server() const { return _server; }
        const std::string &     languageId() const { return _languageId; }
        const std::string &     file_name() const { return _file_name; }

    public:
        bool open(const variable::Object &textDocument_object);
        bool change(const variable::Object &doc_params);
        bool close();
        bool analyze();
        void copyContent(std::u16string &content) const;
        bool checkDependency(const std::string &uri);

    public:
        variable::Value produceHoverResponse(const lsp::Position &pos);
        variable::Value produceGotoDeclarationResponse(const lsp::Position &pos);
        variable::Value produceGotoDefinitionResponse(const lsp::Position &pos);
        variable::Value produceCompletionResponse(const lsp::CompletionParams &completionParams);
        variable::Value produceSemanticTokensResponse();
        variable::Value produceDocumentSymbolsResponse();
        variable::Value produceSimodoCommandResponse(const std::u16string & command_name);

    public:
        variable::Value makeDiagnosticParams(const std::vector<MessageFullContent> & message_set) const;
        static std::shared_ptr<variable::Object> 
                        makeRange(const inout::Location & loc);
        static std::shared_ptr<variable::Object> 
                        makeRange(std::pair<int64_t, int64_t> start, std::pair<int64_t, int64_t> end);
        static std::shared_ptr<variable::Object> 
                        makeRange(const inout::Range & range);
        static std::shared_ptr<variable::Object> 
                        makePosition(int64_t line, int64_t character);
        static int64_t  makeSeverity(inout::SeverityLevel level);
        static std::u16string makeMessage(const MessageFullContent & message);

        std::string     convertUriToPath(const std::string & uri);
    };

}

#endif // DocumentContext_h